#include "shell.h"
#include "user.h"
#include "commands.h"
#include "files.h"
#include "../std/systemcall.h"
#include "../std/stdio.h"
#include "../std/string.h"
#include "../std/screen_shot.h"
#include "../std/file_common.h"
#include "../std/errno.h"


#define COMAND_LINE_MAX 1000
#define SHELLS 4


#define ECHOserver_fifo "ECHOserver_fifo"
#define Mserver_fifo "Mserver_fifo"

/*
Nombre de usuario y de la maquina.
*/
char name[NAME_MAX_LENGTH] = "system";
char * pcname = "itba";

/*
Pantallas de las distintas terminales,y posicion del cursor.
*/
int cursor[SHELLS];
int16_t screen_shot[SHELLS][2001];

/*
Pids de las terminales.
*/
int shell_vector[SHELLS];

/*
Shel que se esta ejecutando, y la que va a ejecutar despues.
*/
int actual_shell=0;
int next_shell;

int init_count=0;


/*
elimina espacios repetidos, y espacios del principio y del final de un string.
*/
char * strnormalise(char * str) {
    int j, i;
    // cambia enters por espacios
    for (j = 0; str[j] != '\0'; j++) {
        if (str[j] == '\n' || str[j] == '\t') {
            str[j] = ' ';
        }
    }
    // elimina espacios del principio
    while (str[0] == ' ') {
        str = str + 1;
    }
    //elimina espacios del final
    for (i = strlen(str) - 1; i > 0 && str[i] == ' '; i--) {
        str[i] = '\0';
    }
    //elimina espacios repetidos en el medio
    for (j = 0; str[j] != '\0'; j++) {
        if (str[j] == ' ' && str[j + 1] == ' ') {
            strcpy(str + j, str + j + 1);
            j--;
        }
    }
    return str;
}


void printuser() {
    printf("\x1B[36;1m%s@%s.%d:%s$ \x1B[0m", name, pcname,actual_shell,getPath());
}

char * getUserName(){
	return name;
}

void setUserName(char * newName){
	strcpy(name, newName);
}

/*
parametros: comand - nombre del comando a ejecutar.
argcant y argv - parametros a pasarle al main del nuevo proceso.
background - flag que indica si la aplicacion va a correr en background o no.

Ejecuta un comando.

retorna: el valor de retorno del proceso.
*/
int execute(char* comand, char * argvec[],int background) {
	/*
	Si no hay comando, no hago nada.
	*/
	if (comand[0] == '\0') {
		return 0;
	}
	
	/*
	busco el main del programa, y si no tiene, imprimo un mensaje y retorno.
	*/
	main start = get_command(comand);
	if (start == NULL) {
		printf("invalid comand: %s\n", comand);
		return -1;
	}
	
	/*
	Creo el nuevo proceso.
	*/
	int pid=fork(start,argvec);
	setname(comand,pid);
	int stat=0;
	
	/*
	Si no corre en background, me quedo esperando a que termine.
	*/
	killzombies();
	
	if(!background){
		while(__waitpid(-1 ,&stat)==-1);
	}

	/*
	retorno el valor de retorno del programa.
	*/
	return stat;
}

/*
Lee de la entrada estandart, y ejecuta el comando entrado.
*/
int parseline() {

    char c;
    int i = 0;
    char comand_line[COMAND_LINE_MAX];
    
    /*
    Leo caracteres hasta que me encuentre con un enter, o con un &, o me quede sin espacio en el buffer.
    */
    while ((c = getchar()) != '\n' && c != '&' && i < COMAND_LINE_MAX - 3) {
        comand_line[i] = c;
        i++;
    }
    
    /*
    Si sali del ciclo anterior y no fue por un enter, me quedo leyendo hasta que me llegue un enter.
    */
    if (c=='&' || i >= COMAND_LINE_MAX - 3) {
        while (getchar() != '\n');
        if(i >= COMAND_LINE_MAX - 3){
        	printf("\n");
        }
    }
    comand_line[i] = '\0';
    
    /*
    Elimino espacios sobrantes.
    */
    char* command = strnormalise(comand_line);
    
    /*
    Armo el vector de argumentos.
    Por cada espacio que no este entre comillas, separo los argumentos,
    lo que esta entre comillas, pasa a ser todo un mismo argumento.
    */
    int argcant = 0;
    char * argvec[50];
    int in_quotes = 0;
    for (i = 0; command[i] != '\0'; i++) {
        if (command[i] == ' ' && !in_quotes) {
		command[i] = '\0';
		argvec[argcant] = &command[i + 1];
		argcant++;
        } else if (command[i] == '"') {
            if(!in_quotes) {
                argvec[argcant-1] = &command[i + 1];
            }
            command[i] = '\0';
            in_quotes = !in_quotes;
        }
    }
     argvec[argcant]=NULL;
    /*
    Ejecuto el programa.
    */
    execute(command, argvec, c=='&');
    return 0;
}




/*
Comando que imprime sus argumentos, uno en cada renglon.
*/
int echo_shell(int argc, char* argv[]) {
    int i;
    for (i = 0; i < argc; i++) {
        printf("%s\n", argv[i]);
    }
    printf("\n");
    return 0;
}



/*
Comando que limpea la pantalla.
*/
int clear_shell(int argc, char* argv[]) {
   printf("\x1B[2J");
   return 0;
}

/*
Comando que dado su primer argumento dice si es par o impar.
*/
int isodd_shell(int argc, char* argv[]) {
    if (argc < 1) {
        printf("Usage: isodd <number>\n");
        return -1;
    }
    int number;
    sscanf(argv[0], "%d", &number);

    if (number % 2 == 0) {
        printf("The number %d is NOT ODD, its EVEN.", number);
    } else {
        printf("The number %d is ODD", number);
    }
    printf("\n");
    return 0;
}

/*
Comando que muestra los comandos disponibles.
*/
int help_shell(int argc, char* argv[]) {
    printf("\x1B[33mThese are the commands available: \x1B[0m\n\n");
    command_t *commands = (command_t *)get_command_list();
    int i = 0;
    while (i < get_commands_added()) {
        printf("\x1B[4m%s\x1B[0m", commands[i].name);
        
       	if(strlen(commands[i].name)<4){
        	printf("\t");
        }
        
        printf("    %s", commands[i].help);
        
        int len;
        if(i%2==0 && i+1<get_commands_added() && (len=(strlen(commands[i].help) + strlen(commands[i].name)))<35
        						&& strlen(commands[i+1].help) + strlen(commands[i+1].name)< 35 ){

        	while(35>len++)
        		printf(" ");
        }
        else{
        	printf("\n");
        }
        i++;
    }
    printf("\n\nPress CTRL+ALT+SUPR to reboot the system\n");
    return 0;
}



static void test_shell_print_usage(){
    printf("Usage: test <testcase>.\n");
    printf("testcases:\n\tprintf\n\tscanf\n");
}

/*
Pedido por arqui, un comando que testee el printf y el scanf.
*/
int test_shell(int argc, char* argv[]) {
    if (argc < 1) {
        test_shell_print_usage();
        return -1;
    }
    int integer;
    unsigned int uinteger;
    char* string;
    char chr;
    
    if (!strcmp(argv[0], "printf")) {
        printf("\x1B[32mPlease verify the OKval is the same as RETval\n\x1B[1mNOTATION: case[OKval]: RETval\x1B[0m");
        printf("\n");
        printf("string[hola mundo]: %s", "hola mundo");
        printf("\n");
        printf("char[c]: %c", 'c');
        printf("\n");
        printf("integer[-123]: %d", -123);
        printf("\n");
        printf("unsigned integer[123]: %u", 123);
        printf("\n");
        printf("hexa[FFFFFFFF]: %x", -1);
        printf("\n");
    } else if (!strcmp(argv[0],"scanf")) {
        printf("\x1B[32mPlease verify the OKval is the same as RETval\n\x1B[1mNOTATION: case[OKval]: RETval\x1B[0m");
        printf("\n");
        sscanf("-123", "%d", &integer);
        printf("integer[-123]: %d", integer);
        printf("\n");
        sscanf("123", "%u", &uinteger);
        printf("unsigned integer[123]: %u", uinteger);
        printf("\n");
        sscanf("hello world scanf", "hello %s scanf", string);
        printf("string[world]: %s", string);
        printf("\n");
        sscanf("c", "%c", &chr);
        printf("char[c]: %c", chr);
    } else {
        test_shell_print_usage();
        return -1;
    }
    printf("\n");
    return 0;
}

/*
Comando que imprime muchas b en pantalla.
*/
int printb_shell(int argc, char* argv[]){
  int i;
  for(i=0;i<2000;i++){
    printf("b");
  }
  printf("\n");
  return 0;
}

int malloc_shell(int argc, char* argv[]){
	
  printf("\n");
  
   char * chau = (char*)malloc(5000);
   strcpy(chau, "primero");
   printf("%s\n", chau);
   
      infoMem(chau);
   
 //  freeMem(chau);
 //  freeMem(chau2);
  // freeMem(cha);
  // freeMem(chau1);
 //  freeMem(chau2);
   
  // infoMem(chau2);
   /*
   char * chau2 = (char*)malloc(sizeof(char)*1024);
   strcpy(chau2, "tercero");
   printf("%s\n", chau2);
   
   char * chau3 = (char*)malloc(sizeof(char)*1024);
   strcpy(chau3, "cuarto");
   printf("%s\n", chau3);
   
   freeMem(chau2);
   freeMem(chau3);*/

  
}

	unsigned int heap_end;
	unsigned int stack_start;
	unsigned int esp;
  
int pageinfo_shell(int argc, char* argv[]){
	if(argc<1){
		printf("Usage: pageinfo <pid>.\n");
		return -1;
	}
	
	heap_end=heaplimit(*argv[0]-'0');
	
	stack_start=stacklimit(*argv[0]-'0');
	
	if(heap_end==0 || stack_start==0){
		printf("unexistent proces\n");
		return -1;
	}
	
	printf("******************** 0\n");
	printf("*kernel space      *(1024 paginas)\n");
	printf("******************** 400000\n");
	printf("*cache directory   *(1024 paginas)\n");
	printf("******************** 800000\n");
	printf("*DD directory      *(1024 paginas)\n");
	printf("******************** C00000\n");	
	printf("*heap              *(%u paginas)\n",(heap_end-0xC00000)>>12);
	printf("******************** %x\n",heap_end);	
	printf("*free              *(%u paginas)\n",(stack_start-heap_end)>>12);
	printf("******************** %x\n",stack_start);
	printf("*stack             *(%u paginas)\n",(0xFFFFFFFF-stack_start)>>12);
	printf("******************** FFFFFFFF\n");
	
	return 0;
}
  
  
/*
Comando que imprime muchas a en pantalla.
*/
int printa_shell(int argc, char* argv[]){
  int i;
  for(i=0;i<2000;i++){
    printf("a");
  }
  printf("\n");
  return 0;
}

/*Comando edit para crear/editar un archivo. Primer parametro nombre del archivo, segundo el contenido*/
int edit_shell(int argc, char* argv[]){
  
	if(argc<2){
		printf("Usage: edit <file> <content>.\n");
		return -1;
	}
	
	int fd=open(argv[0],O_CREATE | O_EXCL | O_WR);
	
	
	/**/
	char fileName[FILE_NAME];
	getLastNode(fileName, argv[0]);
  	
	char Dname[FILE_NAME];
  	getParentPath(Dname, argv[0]);

	if(strlen(Dname)== 0){
		strcpy(Dname,".");
	}
	
	int Ddir=open(Dname,0);
	
  	int sector = getSector(Ddir,fileName);
  	
  	
	/*Si no existe el archivo salgo*/
	if(sector == -1 ){	
		printf("%s: File  doesn't exist\n", argv[0]);
		return -1;	
	}
	
	File_info info;
	finfo(sector,&info);
	
	
	if(info.type == DIRECTORY_TYPE){
		printf("edit: %s: Is a directory.\n", fileName);
		return -1;	  
	}
	
	if(info.type != FIFO_TYPE){
		getLinkPath(argv[0]);	
	}
	
	/**/
	
	char Oname[FILE_NAME];
	int origenDir;
	
	getParentPath(Oname, argv[0]);
	
	/*Si es link lo resuelvo*/
	getLinkPath(Oname);

	if(strlen(Oname)== 0){
		strcpy(Oname,".");
	}
	
	origenDir=open(Oname,0);
	if(origenDir==-1){
		printf("edit: error:%s\n",strerror(errno));
		return -1;
	}
	
	if(fd==-1){
		fd=open(argv[0],O_WR);
	}
		
	
	if(fd==-1){
		printf("edit: couldent open the file ¿?\n");
		return -1;
	}
	
	__write(fd,argv[1],strlen(argv[1]));
	
	close(fd);
	return 0;
}

/*Crea un archivo grande. El primer argumento es el nombre del archivo a crear*/
int bigfile_shell(int argc, char* argv[]){
  
	if(argc<1){
		printf("Usage: bigfile <file>.\n");
		return -1;
	}
	
	int fd=open(argv[0],O_CREATE | O_WR);
	
	if(fd==-1){
		printf("edit: couldent open the file\n");
		return -1;
	}
	
	char text[11] = "ABCDEFGHIJ";
	
	int i;
	for(i=0; i < 820 ; i++)
		__write(fd,text,strlen(text));
	
	close(fd);
	return 0;
}

int size_shell(int argc, char* argv[]){
  
	if(argc<1){
		printf("Usage: size <file>.\n");
		return -1;
	}
	
	int fd=open(argv[0],0);
	
	if(fd==-1){
		printf("edit: couldent open the file\n");
		return -1;
	}
	
	char buff[512];
	int size=0;
	int num=1;	
	while(num!=0){
		if((num = __read(fd,buff,512))==-1){
			printf("cp: %s: could not read the file\n", argv[0]);
			close(fd);
			return 1;
		}
		size+=num;
	}
	close(fd);
	
	printf("The size is: %d\n", size);
	return 0;
}

/*Ver el contenido del archivo pasado como primer parametro.*/
int view_shell(int argc, char* argv[]){
	if(argc<1){
		printf("Usage: view <file>\n");
		return -1;
	}
	
	/*Si es link lo resuelvo*/
	getLinkPath(argv[0]);
	
	char Oname[FILE_NAME];
	int origenDir;
	
	getParentPath(Oname, argv[0]);

	if(strlen(Oname)== 0){
		strcpy(Oname,".");
	}
	
	origenDir=open(Oname,0);
	if(origenDir==-1){
		printf("view: error:%s\n",strerror(errno));
		return -1;
	}
	
	char fileName[FILE_NAME];
	getLastNode(fileName, argv[0]);
	int sector = getSector(origenDir, fileName);
	
	if(sector != -1){
		File_info file;
		finfo(sector,&file);
	
		if(file.type != FILE_TYPE){
			printf("view: %s: Is not a regular file.\n", fileName);
			return -1;	  
		}
	}
	
	int fd=open(argv[0],O_RD);
	
	if(fd==-1){
		printf("view: error:%s\n",strerror(errno));
		return 1;
	}
		
	
	
	char buff[50];
	
	int num=1;
	
	while(num!=0){
		if((num = __read(fd,buff,49))==-1){
			printf("view: read error");
			return 1;
		}
	
		buff[num]='\0';
	
		int i;
		for(i=0;i<num;i++){
			printf("%c",buff[i]);
		}
	}
	printf("\n");
	
	close(fd);
	
	return 0;
}


int Mserver_shell_aux(int argc, char* argv[]){
	
	int fd_in=*argv[0];
	int fd_out=*argv[1];
	char c='\0';
		
	while(c!='\n'){
		__read(fd_in, &c,1);
		if(c<='z' && c>='a'){
			c+='A'-'a';
		}
		__write(fd_out,&c,1);
	}
	close(fd_in);
}

void Mserver_exit(int sig){
	_rm(Mserver_fifo);
	exit(2);
}

int Mserver_shell(int argc, char* argv[]){
	signal(9,Mserver_exit);
	mkfifo(Mserver_fifo);
	int fd_in=open(Mserver_fifo, 0);
	char name[22];

	
	char fd_in_string[1];
	char fd_out_string[1];
	
	char* argvec[2];
	argvec[0]=fd_in_string;
	argvec[1]=fd_out_string;
	
	
	while(1){
		__read(fd_in,name,22);
		
		int fd_out=open(name,0);
		
		if(fd_out!=-1){
			int i;	
			for(i=0;i<strlen(Mserver_fifo);i++){
				name[i]=Mserver_fifo[i];
			}
		
			mkfifo(name);
			int fd_new=open(name, 0);
		
			fd_in_string[0]=fd_new;
		
			fd_out_string[0]=fd_out;

			fork(Mserver_shell_aux, argvec);
			close(fd_new);
			_rm(name);
		}
		close(fd_out);
	}
	close(fd_in);
	_rm(Mserver_fifo);
	
	return 0;
}

int whileINF_shell(int argc, char* argv[]){
	while(1);
}


void ECHOserver_exit(int sig){
	_rm(ECHOserver_fifo);
	exit(2);
}


int ECHOserver_shell(int argc, char* argv[]){
	signal(9,ECHOserver_exit);

	
	mkfifo(ECHOserver_fifo);
	
	int fd_in=open(ECHOserver_fifo, 0);
	
	char c;
	
	while(c!='Q'){
		__read(fd_in,&c,1);
		printf("%c",c);
	}
	_rm(ECHOserver_fifo);
	printf("uit echo server\n");
}

int Mclient_shell(int argc, char* argv[]){
	int pid = getpid();
	
	char buff[10];
	int i=0;
	while(pid>0){
		buff[i++]='0'+pid%10;
		pid/=10;
	}
	
	char name[22];
	char name1[22];
	
	strcpy(name, "Mclient_fifo");
	strcpy(name1,"Mserver_fifo");
	
	name[i+12]='\0'; 
	name1[i+12]='\0'; 
	
	for(i--;i>=0;i--){
		name[12+i]=buff[i];
		name1[12+i]=buff[i];
	}
	
	mkfifo(name);
	
	
	int fd_in=open(name, 0);
	int fd_out=open("Mserver_fifo", 0);
	
	if(fd_out==-1){
		printf("No Mserver fifo found\n");
	}
	
	char c;
	
	__write(fd_out,name,22);
	
	close(fd_out);
	mkfifo(name1);
	fd_out=open(name1,0);
	
	while(c!='\n'){
		c=getchar();
		__write(fd_out,&c,1);
		__read(fd_in,&c,1);
		putchar(c);
	}
	close(fd_in);
	close(fd_out);
	_rm(name);
	_rm(name1);
	
	return 0;
	
}

int kill_shell(int argc, char* argv[]){
	if (argc < 1) {
		printf("Usage: kill <pid>.\n");
		return -1;
    	}
    	int pid;
	sscanf(argv[0],"%d",&pid);
	kill(pid,9);
	
	return 0;
}

void rec1(int i){
	if(i==4096*4){
		printf("llegue!\n");
		return;
	}
	char basura[512];
	if(i%3){
		yeld();
	}
	rec1(i+1);
	return;
}

int stackrec1_shell(int argc, char* argv[]){
	int i=0;
	rec1(i);
	return 0;
}

int rec2(){
	char c;
	char basura[512];
	strcpy(basura,"basura");
	while(1){
		c = getchar();
		if(c=='+'){
			yeld();
			if (rec2()){
				return 1;
			}
		}else if(c=='q'){
			printf("Quit\n");
			return 1;
		}else if(c=='m'){
			printf("posicion de memoria:%u\n",(unsigned)&basura);
		}
	}
}

int stackrec2_shell(int argc, char* argv[]){
	rec2();
	return 0;
}




int mallocheap_shell(int argc, char* argv[]){
	char c;
	char* m=0;
	while(	(c = getchar()) != 'q'){
		if(c=='+'){
			m=malloc(512);
			strcpy(m,"basura");
		}
		if(c=='m'){
			printk("posicion de memoria:%u\n",(unsigned)m);
		}
	}
	return 0;
}


int top_shell(int argc, char* argv[]){
	top_t t;
	
	top(&t);
	
	
	printf("Tasks: %d total, %d running, %d sleeping, %d zombie\n\n",
	t.running + t.blocked + t.ready + t.zombies, t.running + t.ready, t.blocked, t.zombies);
	
	printf("\x1B[30;47mPID\t\tstate\t\t%%cpu\t\tname\n\x1B[0m");
	int i;
	for(i=0;i<t.cant;i++){
		printf("%d\t\t%s\t\t%d\t\t%s\n",t.processes[i].pid,t.processes[i].state,t.processes[i].porcentage,t.processes[i].name);
	
	}
	
	return 0;

}
/*
Comando que ejecuta los dos comandos de arriva simultaneamente, hecho para mostrar como anda el multitasker.
*/
int printab_shell(int argc, char* argv[]){
	fork(printb_shell,NULL);
	fork(printa_shell,NULL);
}

/*
keylisteners, que permiten el cambio de shell. corren en el kernel, asique son una gran amenaza a la seguridad,
peo supongo que no nos tenemos que preocupar por eso en este trabajo.
Guardan cual es la proxima shell a ejecutar (dependiendo de cntrl + que numero hayas apretado), y envian una
señal a la shell que esta corriendo, para que haga el cambio.
*/
int change_shell1(){
	next_shell=0;
	if(next_shell!=actual_shell)
		kill(shell_vector[actual_shell],1);
	return 0;
}

int change_shell2(){
	next_shell=1;
	if(next_shell!=actual_shell)
		kill(shell_vector[actual_shell],1);
	return 0;
}

int change_shell3(){
	next_shell=2;
	if(next_shell!=actual_shell)
		kill(shell_vector[actual_shell],1);
	return 0;
}

int change_shell4(){
	next_shell=3;
	if(next_shell!=actual_shell)
		kill(shell_vector[actual_shell],1);
	return 0;
}

/*
manejador de señal, que cambia la shel que esta ejecutando.
*/
void sig_handler(int sig){
	/*
	Guarda la pantalla y la posicion del cursor ctual.
	*/
	get_screen(screen_shot[actual_shell],&cursor[actual_shell]);
	
	/*
	Despierta a la proxima shell a ejecutar.
	*/
	wakeup(shell_vector[next_shell]);
	
	/*
	Se duerme.
	*/
	sleep2();
	
	/*
	Se declara la shell actual.
	*/
	actual_shell=next_shell;
	
	/*
	Carga la pantalla y la posicion del cursor.
	*/
	set_screen(screen_shot[actual_shell],cursor[actual_shell]);
	
	
	usemytty();
}


/*
Inicializador de la shell.
En argc recive el numero de shell que le corresponde(aunque no es muy lindo, es mas facil).
*/
int shell_start(int argc, char* argv[]) {

	int shell=*argv[0]-'0';
	newstdio();
	/*
	Setea el cambio de shell como el manejador de la señal 1.
	*/
	signal(1,sig_handler);
	
	/*
	Si no es la shell 0 se duerme.
	Esto es para que quede una sola shell ejecutando.
	*/
	
	init_count++;
	if(init_count<SHELLS){
		sleep();
		int y;
		for(y=0;y<20000;y++);
	}
	actual_shell=shell;
	usemytty();
	
	
	printf("\x1B[2J\x1B[33mWelcome to arnix (ARg uNIX) %s!\x1B[0m\n\nYou may type \x1B[1mhelp\x1B[0m for more information\n\n", name);

	/*
	Ciclo de la shell.
	*/
	while (1) {
		printuser();
		parseline();
	}
}


/*
Crea las shells, y setea los key listener.
*/
int shells_init(int argc, char* argv[]){

	newstdio();
	usemytty();
	/*
	Agrega todos los comandos.
	*/
	add_command("test", test_shell, "test cases for functionality");
	add_command("echo", echo_shell, "echoes some text, don't forget the quotes (\") if you use spaces");
	add_command("clear", clear_shell, "clears the screen");
	add_command("isodd", isodd_shell, "tells if the number is odd or not");
	add_command("printa", printa_shell, "prints lots of nice litle a`s");
	add_command("printb", printb_shell, "prints lots of nice litle b`s");
	add_command("printab", printab_shell, "prueba fork");
	add_command("cd", cd_shell, "change current directory");
	add_command("rm", rm_shell, "remove a file or directory");
	add_command("chmod", chmod_shell, "change file permissions");
	add_command("mv", mv_shell, "change file name or address");
	add_command("passwd", passwd, "change the user password");
	add_command("group", group, "change the user group");
	add_command("logout", logout, "logout");
	add_command("adduser", newUser, "New User");
	add_command("ls", ls_shell, "files list");
	add_command("mkdir", mkdir_shell, "create directory");
	add_command("ln", ln_shell, "create a link");
	add_command("top",top_shell, "display arnix tasks");
	add_command("kill",kill_shell, "fullminates a tasks");
	add_command("edit",edit_shell, "inits new file");
	add_command("cp",cp_shell, "copy a file");
	add_command("bigfile",bigfile_shell, "create a big file");
	add_command("size",size_shell, "size of file");
	add_command("view",view_shell, "shows file content");
	add_command("Mserver",Mserver_shell, "server que pasa a mayuscula");
	add_command("Mclient",Mclient_shell, "cliente de Mserver");
	add_command("format",format_shell, "formats the disk");
	add_command("help", help_shell, "shows help");
	add_command("ECHOserver",ECHOserver_shell, "echo server");
	add_command("whileINF",whileINF_shell, "proceso que cuelga hasta que lo matan");
	add_command("malloc",malloc_shell, "Testeo del malloc");
	add_command("stackrec1",stackrec1_shell, "Testeo de stack");
	add_command("stackrec2",stackrec2_shell, "Testeo de stack 2");
	add_command("mallocheap",mallocheap_shell, "Testeo del malloc 2");
	add_command("pageinfo",pageinfo_shell, "muestra infomacion sobre el mapa de paginas");
	
	
	int i=0;
	login();

	char* argvec[4][2];
	
	argvec[0][0]="0";
	argvec[0][1]=NULL;
	
	argvec[1][0]="1";
	argvec[1][1]=NULL;
	
	argvec[2][0]="2";
	argvec[2][1]=NULL;
	
	argvec[3][0]="3";
	argvec[3][1]=NULL;
	
	/*
	Setea los keylisteners.
	*/
	add_key_listener(1,2, change_shell1);
	add_key_listener(1,3, change_shell2);
	add_key_listener(1,4, change_shell3);
	add_key_listener(1,5, change_shell4);
	
	/*
	Crea las shells.
	*/
	for(i=0;i<SHELLS;i++){
		int j=fork(shell_start,argvec[i]);
		setname("shell",j);
		shell_vector[i]=j;
	}
	
	
	return 1;
}

